﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Data.Sql;
using System.Data.Common;
using System.Collections;
using System.Windows.Forms;
using System.Configuration;


namespace Conexiones
{
    public class Conexion
    {
        #region Propiedades publicas
        public bool limpiaString = false;
        public string Error = " ";
        public string Motor = " ";
        public DataTable Dt
        {
            get { return loDt; }
            set { loDt = value; }
        }
        public Dictionary<string, Hashtable> Esquema = new Dictionary<string, Hashtable>();
        public Dictionary<string, string> Value = new Dictionary<string, string>();
        #endregion

        #region Propiedades Privadas
        private DbConnection dbcon;
        private DbDataAdapter dbda;
        private DbCommand dbcmd;
        private DbCommandBuilder dbBuilder;
        private DbProviderFactory dbpf;
        private DataTable loDt = new DataTable();
        #endregion

        #region metodos publicos de acceso a datos
        /// <summary>
        /// Constructor del objeto
        /// </summary>
        public Conexion()
        {
            this.Motor = ConfigurationManager.AppSettings.Get("Motor").ToUpper().Trim();
        }
        /// <summary>
        /// Devuelve Data Table en la propiedad loDT
        /// </summary>
        /// <param name="lcSql"></param>
        /// <returns></returns>
        public bool ejecutar(string lcSql)
        {
            return ejecutar("DATOS", lcSql);
        }
        /// <summary>
        /// Devuelve Data Table en la propiedad loDT
        /// </summary>
        /// <param name="lcBase"></param>
        /// <param name="lcSql"></param>
        /// <returns></returns>
        public bool ejecutar(string lcBase, string lcSql)
        {
            if (limpiaString)
            {
                lcSql = MisFunciones.ChrTran(lcSql, "\n", " ");
                lcSql = MisFunciones.ChrTran(lcSql, "\r", " ");
                lcSql = MisFunciones.ChrTran(lcSql, ";", " ");
            }

            DbProviderFactory dbpf;
            DbConnection dbcon;
            DbCommand dbcmd;
            DbDataAdapter dbda;


            bool lRta = true;

            /** Obtengo el motor de la base de datos y la configuracion */
            this.Motor = ConfigurationManager.AppSettings.Get("Motor").ToUpper().Trim();
            string lsMotor = this.Motor + lcBase.ToUpper().Trim();

            string lsConnectionString = ConfigurationManager.ConnectionStrings[lsMotor.ToUpper()].ConnectionString;
            string lsProvider = ConfigurationManager.ConnectionStrings[lsMotor.ToUpper()].ProviderName;




            try
            {
                // Obtengo el proovedor.
                dbpf = DbProviderFactories.GetFactory(lsProvider);
                // Creo la conexión y el comando.
                dbcon = dbpf.CreateConnection();

                // Le asigno la cadena
                dbcon.ConnectionString = lsConnectionString;

                // Ahora con un DataAdaptater
                dbda = dbpf.CreateDataAdapter();

                //*** Abro la conexion ***//    
                dbcon.Open();

                //*** Crea el comando a ser usado ***//
                dbcmd = dbpf.CreateCommand();
                dbcmd.CommandType = CommandType.Text;
                //*** Asigna el comando sql que ejecutará ***//
                dbcmd.CommandText = lcSql;
                dbcmd.Connection = dbcon;

                dbcmd.ExecuteNonQuery();
                dbcon.Close();

                lRta = true;
            }
            catch (SqlException e)
            {
                this.Error = "No se ejecuto la instuccion en el Servidor \n Motivo: " + e.Message;
                lRta = false;
            }
            catch (Exception e)
            {
                this.Error = "No se ejecuto la instuccion en el Servidor \n Motivo: " + e.Message;
                lRta = false;
            }
            return lRta;
        }
        /// <summary>
        /// Obtiene un datatable de la tabla y base de datos pasada como parametros
        /// </summary>
        /// <param name="lcBase"></param>
        /// <param name="Tabla"></param>
        /// <returns> bool indicando si la pudo abrir, mensaje de error en propiedad error</returns>
        public bool Generar_DataTable(string lcBase, string Tabla)
        {
            DataTable schemaTable;
            DbDataReader myReader;
            bool lRta = true;

            try
            {

                /** Obtengo el motor de la base de datos y la configuracion */
                this.Motor = ConfigurationManager.AppSettings.Get("Motor").ToUpper().Trim();
                string lsMotor = this.Motor + lcBase.ToUpper().Trim();

                string lsConnectionString = ConfigurationManager.ConnectionStrings[lsMotor.ToUpper()].ConnectionString;
                string lsProvider = ConfigurationManager.ConnectionStrings[lsMotor.ToUpper()].ProviderName;

                // Obtengo el proovedor.
                dbpf = DbProviderFactories.GetFactory(lsProvider);

                // Creo la conexión y el comando.
                dbcon = dbpf.CreateConnection();

                // Le asigno la cadena
                dbcon.ConnectionString = lsConnectionString;

                // Ahora con un DataAdaptater
                dbda = dbpf.CreateDataAdapter();

                // Abro la conexion
                dbcon.Open();

                //*** Crea el comando a ser usado ***//
                dbcmd = dbpf.CreateCommand();
                dbcmd.CommandType = CommandType.Text;
                dbcmd.CommandText = "select * from " + Tabla;
                dbcmd.Connection = dbcon;

                //*** Crea el Data Adapter ***//
                dbda = dbpf.CreateDataAdapter();
                dbda.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                dbda.SelectCommand = dbcmd;
                dbda.AcceptChangesDuringFill = true;
                dbda.AcceptChangesDuringUpdate = true;

                //*** Crea el buider con el Factory      ***//
                //*** Le asigna que data adapter trabaja ***//
                dbBuilder = dbpf.CreateCommandBuilder();
                dbBuilder.DataAdapter = dbda;

                //*** Arma los comandos de Sql para que use el adapter ***//
                dbda.InsertCommand = dbBuilder.GetInsertCommand(true);
                dbda.UpdateCommand = dbBuilder.GetUpdateCommand(true);
                dbda.DeleteCommand = dbBuilder.GetDeleteCommand(true);

                //*** Llena los datos
                dbda.Fill(loDt);

                //*** Setea los datos regionales ***//
                System.Globalization.CultureInfo myCI = new System.Globalization.CultureInfo("es-AR", false);
                loDt.Locale = myCI;

                //*** Lleno el esquema para consultar los tipos
                try
                {
                    dbda.FillSchema(loDt, SchemaType.Source);
                }
                catch
                { }

                #region Guarda el schema de la tabla en las propiedades
                // Ejecuta el reader para obtener el schema
                myReader = dbcmd.ExecuteReader();

                // Lee El schema
                schemaTable = myReader.GetSchemaTable();

                // Arma el diccionario con las propiedades
                foreach (DataRow Campo in schemaTable.Rows)
                {
                    Hashtable hPropiedad = new Hashtable();
                    foreach (DataColumn Propiedad in schemaTable.Columns)
                    {
                        hPropiedad.Add(Propiedad.ColumnName.ToUpper(), Campo[Propiedad].ToString());
                    }
                    Esquema.Add(Campo["ColumnName"].ToString().ToUpper(), hPropiedad);
                }
                myReader.Close();
                #endregion

                #region Consulta si permite valores null la base de datos
                foreach (DataColumn oDc in loDt.Columns)
                {
                    // Busco en el esquema si hay algun campo autoincremental     
                    if (this.ObtenerPropiedad(oDc.ColumnName, "AllowDBNull") == "true")
                        loDt.Columns[oDc.ColumnName].AllowDBNull = true;
                }
                #endregion

                //*** Cierro la conexion para no tener abierta la conexion mucho tiempo
                dbcon.Close();
                lRta = true;
            }
            catch (SqlException e)
            {
                this.Error = e.Message;
                loDt = null;
                lRta = false;
            }

            catch (Exception e)
            {
                this.Error = e.Message;
                loDt = null;
                lRta = false;
            }
            return lRta;

        }
        /// <summary>
        /// Vuelve a llenar el Data Table
        /// </summary>
        /// <returns></returns>
        public bool Refresh()
        {

            this.Dt.Clear();
            this.dbda.Fill(this.Dt);
            return true;
        }
        /// <summary>
        /// Guarda los datos de la datatable
        /// </summary>
        /// <returns></returns>
        public bool Guardar_DataTable()
        {
            bool lOk = true;
            try
            {
                // Abro la tabla               
                this.dbcon.Open();

                // Le indico al Data adapter como llenar los datos
                this.dbda.AcceptChangesDuringFill = true;
                this.dbda.AcceptChangesDuringUpdate = true;

                // Confirmo los datos en la tabla
                this.dbda.Update(this.loDt);

                // Grabo los datos en el dataset
                this.loDt.AcceptChanges();

                // Indico que termino la edicion
                this.loDt.EndInit();

                // Cierro la conexion
                this.dbcon.Close();
                lOk = true;
            }
            catch (ArgumentOutOfRangeException e)
            {
                this.Error = e.Message;
                return false;
            }
            catch (ArgumentException e)
            {
                this.Error = e.Message;
                return false;
            }
            catch (SqlException e)
            {
                this.Error = e.Message;
                return false;
            }
            catch (Exception e)
            {
                this.Error = e.Message;
                return false;
            }
            return lOk;
        }
        /// <summary>
        /// Obtiene las propiedades del campo
        /// </summary>
        /// <param name="tTabla"></param>
        /// <param name="cNombreCampo"></param>
        /// <param name="cNombrePropiedad"></param>
        /// <returns></returns>
        public string ObtenerPropiedad(string cNombreCampo, string cNombrePropiedad)
        {
            try
            {
                return this.Esquema[cNombreCampo.ToUpper()][cNombrePropiedad.ToUpper()].ToString().ToLower();
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// Pone en value los datos del registro. Value se accede por el nombre del campo
        /// </summary>
        /// <param name="nRegistro"></param>
        /// <returns></returns>
        public bool IrRegistro(int nRegistro)
        {
            try
            {
                for (int i = 0; i < this.loDt.Columns.Count; i++)
                {
                    string lcCampo = this.loDt.Columns[i].ColumnName;
                    string lcValor = this.loDt.Rows[nRegistro - 1][i].ToString();
                    if (this.Value.ContainsKey(lcCampo))
                        this.Value[lcCampo] = lcValor;
                    else 
                        this.Value.Add(lcCampo, lcValor);
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// Devuelve un Datarows con las coincidencias
        /// </summary>
        /// <param name="strExpr"></param>
        /// <returns></returns>
        public DataRow[] Filtrar(string strExpr)
        {
            return  this.Dt.Select(strExpr);
    }
        /// <summary>
        /// Devuelve el valor del primer campo que coincide con el filtro
        /// </summary>
        /// <param name="Filtro"></param>
        /// <param name="Campo"></param>
        /// <returns></returns>
        public string Devolver_campo(string Filtro,string Campo)
        {
            DataRow oRow = Filtrar(Filtro)[0];
            return oRow[Campo].ToString();
        }
        /// <summary>
        /// Devuelve el campo del registro actual
        /// </summary>
        /// <param name="Campo"></param>
        /// <returns></returns>
        public string Devolver_campo(string Campo)
        {
            return Value[Campo];
        }
        #endregion
    }
}